package com.starsky.common.utils.file;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;

/**
 * @desc: xml解析工具
 * @author: wangsh
 * @time: 2020/10/14 9:37
 */
public class XmlUtils {

    private static Log log = LogFactory.getLog(XmlUtils.class);

    private static Document doc;
    //文件编码方式
    public static final String CHARSET_UTF8 = "UTF-8";

    /**
     * xmlString 转换成对象
     *
     * @param clazz  转换类
     * @param xmlStr xml字符串
     * @return
     * @throws Exception
     */
    public static Object convertXmlStrToObject(Class clazz, String xmlStr) throws Exception {
        JAXBContext context = JAXBContext.newInstance(clazz);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        StringReader sr = new StringReader(xmlStr);
        return unmarshaller.unmarshal(sr);
    }

    /**
     * 对象转换成xmlString
     *
     * @param obj 对象
     * @return
     * @throws Exception
     */
    public static String convertToXmlStr(Object obj) throws Exception {
        // 创建输出流
        StringWriter sw = new StringWriter();

        // 利用jdk中自带的转换类实现
        JAXBContext context = JAXBContext.newInstance(obj.getClass());

        Marshaller marshaller = context.createMarshaller();
        // 格式化xml输出的格式
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        // 去掉生成xml的默认报文头
        // marshaller.setProperty(Marshaller.JAXB_FRAGMENT,Boolean.TRUE);
        marshaller.setProperty(Marshaller.JAXB_ENCODING, CHARSET_UTF8);
        // 将对象转换成输出流形式的xml
        marshaller.marshal(obj, sw);

        return sw.toString();
    }


    /**
     * xml转map 不带属性
     *
     * @param xmlStr
     * @param needRootKey 是否需要在返回的map里加根节点键
     * @return
     * @throws DocumentException
     */
    public static Map xml2map(String xmlStr, boolean needRootKey) throws DocumentException {
        Document doc = DocumentHelper.parseText(xmlStr);
        Element root = doc.getRootElement();
        Map<String, Object> map = (Map<String, Object>) xml2map(root);
        if (root.elements().size() == 0 && root.attributes().size() == 0) {
            return map;
        }
        if (needRootKey) {
            //在返回的map里加根节点键（如果需要）
            Map<String, Object> rootMap = new HashMap<String, Object>();
            rootMap.put(root.getName(), map);
            return rootMap;
        }
        return map;
    }

    /**
     * xml转map 带属性
     *
     * @param xmlStr
     * @param needRootKey 是否需要在返回的map里加根节点键
     * @return
     * @throws DocumentException
     */
    public static Map xml2MapWithAttr(String xmlStr, boolean needRootKey) throws DocumentException {
        Document doc = DocumentHelper.parseText(xmlStr);
        Element root = doc.getRootElement();
        Map<String, Object> map = (Map<String, Object>) xml2mapWithAttr(root);
        if (root.elements().size() == 0 && root.attributes().size() == 0) {
            return map; //根节点只有一个文本内容
        }
        if (needRootKey) {
            //在返回的map里加根节点键（如果需要）
            Map<String, Object> rootMap = new HashMap<String, Object>();
            rootMap.put(root.getName(), map);
            return rootMap;
        }
        return map;
    }

    /**
     * xml转map 不带属性
     *
     * @param e
     * @return
     */
    public static Map xml2map(Element e) {
        Map map = new LinkedHashMap();
        List list = e.elements();
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                Element iter = (Element) list.get(i);
                List mapList = new ArrayList();

                if (iter.elements().size() > 0) {
                    Map m = xml2map(iter);
                    if (map.get(iter.getName()) != null) {
                        Object obj = map.get(iter.getName());
                        if (!(obj instanceof List)) {
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(m);
                        }
                        if (obj instanceof List) {
                            mapList = (List) obj;
                            mapList.add(m);
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), m);
                    }
                } else {
                    if (map.get(iter.getName()) != null) {
                        Object obj = map.get(iter.getName());
                        if (!(obj instanceof List)) {
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(iter.getText());
                        }
                        if (obj instanceof List) {
                            mapList = (List) obj;
                            mapList.add(iter.getText());
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), iter.getText());
                    }
                }
            }
        } else {
            map.put(e.getName(), e.getText());
        }
        return map;
    }

    /**
     * xml转map 带属性
     *
     * @param element
     * @return
     */
    public static Map xml2mapWithAttr(Element element) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();

        List<Element> list = element.elements();
        List<Attribute> listAttr0 = element.attributes(); // 当前节点的所有属性的list
        for (Attribute attr : listAttr0) {
            map.put("@" + attr.getName(), attr.getValue());
        }
        if (list.size() > 0) {

            for (int i = 0; i < list.size(); i++) {
                Element iter = list.get(i);
                List mapList = new ArrayList();

                if (iter.elements().size() > 0) {
                    Map m = xml2mapWithAttr(iter);
                    if (map.get(iter.getName()) != null) {
                        Object obj = map.get(iter.getName());
                        if (!(obj instanceof List)) {
                            mapList = new ArrayList();
                            mapList.add(obj);
                            mapList.add(m);
                        }
                        if (obj instanceof List) {
                            mapList = (List) obj;
                            mapList.add(m);
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        map.put(iter.getName(), m);
                    }
                } else {

                    List<Attribute> listAttr = iter.attributes(); // 当前节点的所有属性的list
                    Map<String, Object> attrMap = null;
                    boolean hasAttributes = false;
                    if (listAttr.size() > 0) {
                        hasAttributes = true;
                        attrMap = new LinkedHashMap<String, Object>();
                        for (Attribute attr : listAttr) {
                            attrMap.put("@" + attr.getName(), attr.getValue());
                        }
                    }

                    if (map.get(iter.getName()) != null) {
                        Object obj = map.get(iter.getName());
                        if (!(obj instanceof List)) {
                            mapList = new ArrayList();
                            mapList.add(obj);
                            // mapList.add(iter.getText());
                            if (hasAttributes) {
                                attrMap.put("#text", iter.getText());
                                mapList.add(attrMap);
                            } else {
                                mapList.add(iter.getText());
                            }
                        }
                        if (obj instanceof List) {
                            mapList = (List) obj;
                            // mapList.add(iter.getText());
                            if (hasAttributes) {
                                attrMap.put("#text", iter.getText());
                                mapList.add(attrMap);
                            } else {
                                mapList.add(iter.getText());
                            }
                        }
                        map.put(iter.getName(), mapList);
                    } else {
                        // map.put(iter.getName(), iter.getText());
                        if (hasAttributes) {
                            attrMap.put("#text", iter.getText());
                            map.put(iter.getName(), attrMap);
                        } else {
                            map.put(iter.getName(), iter.getText());
                        }
                    }
                }
            }
        } else {
            // 根节点的
            if (listAttr0.size() > 0) {
                map.put("#text", element.getText());
            } else {
                map.put(element.getName(), element.getText());
            }
        }
        return map;
    }

    /**
     * map转xml map中没有根节点的键
     *
     * @param map
     * @param rootName
     * @throws DocumentException
     * @throws IOException
     */
    public static Document map2xml(Map<String, Object> map, String rootName) throws DocumentException, IOException {
        Document doc = DocumentHelper.createDocument();
        Element root = DocumentHelper.createElement(rootName);
        doc.add(root);
        map2xml(map, root);
        return doc;
    }

    /**
     * map转xml map中含有根节点的键
     *
     * @param map
     * @throws DocumentException
     * @throws IOException
     */
    public static Document map2xml(Map<String, Object> map) throws DocumentException, IOException {
        Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator();
        if (entries.hasNext()) { //获取第一个键创建根节点
            Map.Entry<String, Object> entry = entries.next();
            Document doc = DocumentHelper.createDocument();
            Element root = DocumentHelper.createElement(entry.getKey());
            doc.add(root);
            map2xml((Map) entry.getValue(), root);
            return doc;
        }
        return null;
    }

    /**
     * map转xml
     *
     * @param map
     * @param body xml元素
     * @return
     */
    public static Element map2xml(Map<String, Object> map, Element body) {
        Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator();
        while (entries.hasNext()) {
            Map.Entry<String, Object> entry = entries.next();
            String key = entry.getKey();
            Object value = entry.getValue();
            if (key.startsWith("@")) {    //属性
                body.addAttribute(key.substring(1, key.length()), value.toString());
            } else if (key.equals("#text")) { //有属性时的文本
                body.setText(value.toString());
            } else {
                if (value instanceof List) {
                    List list = (List) value;
                    Object obj;
                    for (int i = 0; i < list.size(); i++) {
                        obj = list.get(i);
                        //list里是map或String，不会存在list里直接是list的，
                        if (obj instanceof Map) {
                            Element subElement = body.addElement(key);
                            map2xml((Map) list.get(i), subElement);
                        } else {
                            body.addElement(key).setText((String) list.get(i));
                        }
                    }
                } else if (value instanceof Map) {
                    Element subElement = body.addElement(key);
                    map2xml((Map) value, subElement);
                } else {
                    body.addElement(key).setText(value.toString());
                }
            }
            //System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
        }
        return body;
    }

    /**
     * 格式化输出xml
     *
     * @param xmlStr
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    public static String formatXml(String xmlStr) throws Exception {
        Document document = DocumentHelper.parseText(xmlStr);
        return formatXml1(document);
    }

    /**
     * 格式化输出xml
     *
     * @param document
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    public static String formatXml1(Document document) throws Exception {
        // 格式化输出格式
        OutputFormat format = OutputFormat.createPrettyPrint();
        //format.setEncoding("UTF-8");
        StringWriter writer = new StringWriter();
        // 格式化输出流
        XMLWriter xmlWriter = new XMLWriter(writer, format);
        // 将document写入到输出流
        xmlWriter.write(document);
        xmlWriter.close();
        return writer.toString();
    }


    /**
     * 将文件内容转为document
     *
     * @param xmlString
     * @return
     * @throws DocumentException
     */
    public static Document loadFileByContent(String xmlString) throws DocumentException {
        doc = DocumentHelper.parseText(xmlString);
        return doc;
    }

    /**
     * 将文件转为document
     *
     * @param FilePath
     * @return
     * @throws DocumentException
     */
    public static Document loadFileByPath(String FilePath) throws DocumentException {
        File file = new File(FilePath);
        if (file.exists()) {
            SAXReader reader = new SAXReader();
            doc = reader.read(file); // 读取一个xml的文件
        }
        return doc;
    }

    /**
     * 将文件转为document
     *
     * @param file
     * @return
     * @throws DocumentException
     */
    public static Document loadFile(File file) throws DocumentException {
        SAXReader reader = new SAXReader();
        doc = reader.read(file); // 读取一个xml的文件
        return doc;
    }

    /**
     * 解析xml节点内容
     *
     * @param node       节点
     * @param expression 节点表达式
     * @return
     */
    public static List selectNodes(Node node, String expression) {
        List<Node> nodelist = node.selectNodes(expression);
        return nodelist;
    }

    /**
     * 获取根节点
     *
     * @param doc
     * @return
     */
    public static Element getRootElement(Document doc) {
        Element ele = doc.getRootElement();
        return ele;
    }

    /**
     * 获取节点
     *
     * @param m
     * @param name
     * @return
     */
    public static Element element(Element m, String name) {
        Element ele = m.element(name);
        return ele;
    }

    /**
     * 获取节点
     *
     * @param m
     * @param name
     * @return
     */
    public static List<Element> elements(Element m, String name) {
        List<Element> elist = m.elements(name);
        return elist;
    }

    /**
     * 获取节点
     *
     * @param m
     * @return
     */
    public static List<Element> elements(Element m) {
        List<Element> elist = m.elements();
        return elist;
    }

    /**
     * 获取节点属性
     *
     * @param m
     * @param attriName
     * @return
     */
    public static String attributeValue(Element m, String attriName) {
        String val = m.attributeValue(attriName);
        return val;
    }

    /**
     * 获取节点属性
     *
     * @param m
     * @return
     */
    public static List<String> attributeValues(Element m) {
        List<String> vals = m.attributes();
        return vals;
    }

    /**
     * 创建xml文件内容
     *
     * @param sb1
     * @return
     */
    public static String createSingleXml(String sb1) {
        StringBuilder sb = new StringBuilder();
        sb.append("<root>");
        sb.append(sb1);
        sb.append("</root>");
        sb.append("");
        return sb.toString();
    }

    /**
     * 根据数据创建xml数据串
     *
     * @param map
     * @return
     */
    public static String createValStr(HashMap<String, Object> map) {
        // "	<row UnitID = \"-987654321112\" UnitCode = \"Test123***\" UnitName = \"Test123\" AreaCode = \"440401\" PoliceStationCode = \"Test123\" Status = \"12\" GuildID = \"12\" UnitTypeCode = \"Test123\" CreateTime = \"2015-04-07 11:55:51\" UpdateTime = \"2015-04-07 11:55:51\" ConnTime = \"2015-04-07 11:55:51\" Memo = \"Test123\" Lon = \"113.583700\" Lat = \"22.255030\" Address = \"Test123\" ManufacturerCode = \"Test123\" Integration = \"12\" IsDeleted = \"12\" DeleteTime = \"2015-04-07 11:55:51\" BusinessStatus = \"12\" OpenTime = \"08:12\" CloseTime = \"23:00\" CorporateName = \"Test123\" CorporateCertCode = \"Test123\" CorporateCertType = \"1\" CorporateMobile = \"Test123\" OldUnitCode = \"Test123\" />"
        // +
        if (map == null || map.isEmpty())
            return "";
        StringBuilder vals = new StringBuilder("<row ");
        Set<Map.Entry<String, Object>> sets = map.entrySet();
        Iterator<Map.Entry<String, Object>> it = sets.iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> e = it.next();
            vals.append(e.getKey());
            vals.append("=\"" + e.getValue() + "\" ");
        }
        vals.append(" />");
        return vals.toString();
    }

    public static void main(String[] args) {

        //xml schema解析
        try {
            String path = "E:\\workspace_work\\netbox-doc\\BCP\\导出实例\\145-748836377-410100-410100-1462938002-10000\\GAB_ZIP_INDEX.xml";
            Document doc = XmlUtils.loadFileByPath(path);
            Element e = XmlUtils.getRootElement(doc);
            // List<Element> list = XmlFileOpe.elements(e);
            Element node = (Element) e.selectSingleNode("/MESSAGE/DATASET/DATA/DATASET[@name='WA_COMMON_010013']/DATA");
            // List<Element> list = XmlFileOpe.selectNodes(doc,
            // "/MESSAGE/DATASET/DATA/DATASET[@name='WA_COMMON_010013']");
            System.out.println(((Element) node.selectSingleNode("ITEM[@key='I010032']")).attributeValue("key"));
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

}
